#pragma once

#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include "LockGuard.hpp"

using namespace std;

bool gSave = false;
const string glogname = "log.txt";
pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER;

enum Level
{
    DEBUG = 0,
    INFO,
    WARNING,
    ERROR,
    FATAL
};

void SaveFile(const string &filename, const string &message)
{
    ofstream out;
    out.open(filename, ios::app);
    out << message;
    out.close();
}

string LevelToStr(int level)
{
    switch (level)
    {
    case DEBUG:
        return "Debug";
    case INFO:
        return "Info";
    case WARNING:
        return "Warning";
    case ERROR:
        return "Error";
    case FATAL:
        return "Fatal";
    default:
        return "unknow";
    }
}

string GetTime()
{
    time_t curtime = time(nullptr);
    struct tm *time = localtime(&curtime);
    if (time == nullptr)
    {
        return "None";
    }
    char timebuffer[1024];
    snprintf(timebuffer, sizeof(timebuffer), "%d-%d-%d %d:%d:%d",
             time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
             time->tm_hour, time->tm_min, time->tm_sec);
    return timebuffer;
}

void LogMessage(string filename, int line, bool save, int level, const char *format, ...)
{
    string slevel = LevelToStr(level);
    string stime = GetTime();
    pid_t selfid = getpid();
    char buffer[1024];
    va_list arg;
    va_start(arg, format);
    vsnprintf(buffer, sizeof(buffer), format, arg);
    va_end(arg);
    string message = "[" + stime + "]" + "[" + slevel + "]" +
                     "[" + to_string(selfid) + "]" + "[" + filename + "]" +
                     "[" + to_string(line) + "]" + buffer + "\n";
    LockGuard lock(&glock);
    if (save)
    {
        SaveFile(glogname, message);
    }
    else
    {
        cout << message;
    }
}

#define LOG(level, format, ...)                                              \
    do                                                                       \
    {                                                                        \
        LogMessage(__FILE__, __LINE__, gSave, level, format, ##__VA_ARGS__); \
    } while (false)

#define EnableSave() \
    do               \
    {                \
        gSave = true \
    };               \
    whlie(false)
#define UnableSave()  \
    do                \
    {                 \
        gSave = false \
    };                \
    whlie(false)
    